package com.hmall.item.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;

import com.hmall.item.domain.dto.ItemDTO;
import com.hmall.item.domain.dto.OrderDetailDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.query.ItemPageQuery;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.service.IItemService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author itheima
 */
@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {
    @Autowired
    private RestHighLevelClient client;

    @Override
    public void deductStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
        } catch (Exception e) {
            log.error("更新库存异常", e);
//            return;
            throw new BizIllegalException("库存不足！");
        }
        if (!r) {
            throw new BizIllegalException("库存不足！");
        }
    }

    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
        return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
    }

    /**
     * 搜索商品
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<ItemDTO> search(ItemPageQuery pageQuery) {
        try {
            // 1.创建搜索对象
            SearchRequest searchRequest = new SearchRequest("items");
            // 2.封装搜索条件：搜索框、分类、品牌、价格
            // bool包裹所有查询条件
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            // 2.1 搜索框:如果搜索框有数据，则进行模糊搜索，如果没有数据，则进行match_all
            if (StrUtil.isNotBlank(pageQuery.getKey())){
                boolQuery.must(QueryBuilders.matchQuery("name", pageQuery.getKey()));
            }else {
                boolQuery.must(QueryBuilders.matchAllQuery());
            }

            // 2.2 分类、品牌、价格
            if (StrUtil.isNotBlank(pageQuery.getCategory())){
                boolQuery.filter(QueryBuilders.matchQuery("category", pageQuery.getCategory()));
            }
            if (StrUtil.isNotBlank(pageQuery.getBrand())){
                boolQuery.filter(QueryBuilders.matchQuery("brand", pageQuery.getBrand()));
            }
            if (pageQuery.getMinPrice() != null || pageQuery.getMaxPrice() != null){
                boolQuery.filter(QueryBuilders.rangeQuery("price").from(pageQuery.getMinPrice()).to(pageQuery.getMaxPrice()));
            }

            // 3.指定分页参数0,10;10,10
            searchRequest.source().from((pageQuery.getPageNo()-1) * pageQuery.getPageSize())
                    .size(pageQuery.getPageSize());

            // 4. 指定排序方式和字段
            if (StrUtil.isNotBlank(pageQuery.getSortBy())){
                searchRequest.source().sort(pageQuery.getSortBy(),pageQuery.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
            }

            // 5. 高亮设置
            searchRequest.source().highlighter(
                    SearchSourceBuilder.highlight()
                            .field("name")
                            .requireFieldMatch(false)
            );

            // 6.发送请求，执行搜索
            searchRequest.source().query(boolQuery);
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

            // 7.解析结果：封装dto/解析高亮
            // 定义ist接收dto
            List<ItemDTO> list=new ArrayList<>();

            long total = response.getHits().getTotalHits().value;
            SearchHit[] hits = response.getHits().getHits();
            for (SearchHit hit : hits) {
                ItemDTO itemDTO = JSONUtil.toBean(hit.getSourceAsString(), ItemDTO.class);

                // 解析高亮
                if (hit.getHighlightFields().containsKey("name")){
                    itemDTO.setName(hit.getHighlightFields().get("name").fragments()[0].toString());
                }

                // 添加到集合
                list.add(itemDTO);
            }
            // 计算总页数
            long pages = total % pageQuery.getPageSize() == 0 ? total / pageQuery.getPageSize() : total / pageQuery.getPageSize() + 1;

            // 8.返回结果
            return new PageDTO<>(total, pages, list);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
